﻿using FieldTools.MediaFindOut.Control;
using LibVLCSharp.Shared;
using MediaInfo;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace FieldTools.MediaFindOut
{
    /// <summary>
    /// VLCWindow.xaml 的交互逻辑，暂时只处理本地路径，后续有时间再处理网络路径。vlc兼容性可能比较强，但问题也是最多，暂时封住，就这样了，越写bug越多，有时间用FFmpeg重写
    /// <![CDATA[2024/03/09]]>
    /// </summary>
    public partial class VLCWindow : Window
    {
        #region 初始化
        static ILogger<VLCWindow> logger = new NullLogger<VLCWindow>();
        /// <summary>
        /// 默认构建
        /// </summary>
        public VLCWindow()
        {
            InitializeComponent();
            InIt();
        }
        /// <summary>
        /// 使用MediaInfoWrapper构建
        /// </summary>
        /// <param name="mediaInfos"></param>
        public VLCWindow(List<MediaInfoWrapper> mediaInfos)
        {
            InitializeComponent();
            MediaInfos = mediaInfos;
            InIt();
        }
        /// <summary>
        /// 使用地址集合构建
        /// </summary>
        /// <param name="urls"></param>
        public VLCWindow(List<string> urls)
        {
            InitializeComponent();
            MediaInfos = [];
            foreach (var item in urls)
            {
                MediaInfos.Add(new MediaInfoWrapper(item, logger));
            }
            InIt();
        }
        /// <summary>
        /// 预置数据初始化
        /// </summary>
        private void InIt()
        {
            FastForwardTime = 5000;
            FastReverseTime = 5000;
            UrlIndex = 0;
            ListWidth = 150;

            foreach (var item in MediaInfos)
            {
                var path = GetPathFromMediaInfoWrapper(item);
                if (string.IsNullOrEmpty(path)) continue;
                var name = Path.GetFileName(path);
                MediaUrls.Add(new(name, path));
            }
            if (int.TryParse(ConfigHelper.ReadSetting(nameof(PlayAfterTag)), out int tag))
                PlayAfterTag = tag;
            else
                PlayAfterTag = 1;
            this.DataContext = this;
            this.Loaded += VLCWindow_Loaded;
            this.Closed += VLCWindow_Closed;
        }
        #endregion

        #region 实体
        //readonly static LibVLC libvlc = new([]);
        //static readonly MediaPlayer player = new(libvlc);
        LibVLC? libvlc;
        MediaPlayer? player;
        Media? media;
        /// <summary>
        /// 快进时间
        /// </summary>
        private long FastForwardTime = 5000;
        /// <summary>
        /// 快退时间
        /// </summary>
        private long FastReverseTime = 5000;
        /// <summary>
        /// 播放列表
        /// </summary>
        public List<KeyValuePair<string, string>> MediaUrls { get; set; } = [];
        /// <summary>
        /// 列表宽度
        /// </summary>
        public double ListWidth { get; set; } = 150;
        /// <summary>
        /// 媒体信息集合。MediaInfoWrapper的构造有bug，对于logger写的是可传入为空，但看源码的话实际却没考虑空的情况（比如赋有效的默认值之类的），直接就调用了，必须要传才行，否者会报空引用错误
        /// </summary>
        public List<MediaInfoWrapper> MediaInfos { get; set; } = [
            new("./Assets/Videos/m1.mp4", logger),
            new("./Assets/Videos/m2.mp4", logger),
            new("./Assets/Videos/m3.mp4", logger)
            ];
        private int urlIndex = 0;
        /// <summary>
        /// 列表索引号
        /// </summary>
        public int UrlIndex
        {
            get { return urlIndex; }
            set
            {
                urlIndex = (value >= MediaUrls.Count) ? 0 : (value < 0 ? MediaUrls.Count - 1 : value);
            }
        }
        /// <summary>
        /// 列表是否展开
        /// </summary>
        public bool IsListEx { get; set; } = true;
        /// <summary>
        /// 播放后的行为集合
        /// </summary>
        public static List<KeyValuePair<string, int>> PlayAfterTags => [new("停止", 1), new("重播", 2), new("下一曲", 3)];
        /// <summary>
        /// 播放后的行为,1停止，2重播，3下一曲
        /// </summary>
        public int PlayAfterTag
        {
            get { return (int)GetValue(PlayAfterTagProperty); }
            set
            {
                SetValue(PlayAfterTagProperty, value);
                ConfigHelper.AddUpdateAppSettings(nameof(PlayAfterTag), value.ToString());
            }
        }
        /// <summary>
        /// Using a DependencyProperty as the backing store for PlayAfterTag.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty PlayAfterTagProperty =
            DependencyProperty.Register("PlayAfterTag", typeof(int), typeof(VLCWindow), new PropertyMetadata(1));
        #endregion

        #region 事件
        /// <summary>
        /// 界面关闭，释放资源
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VLCWindow_Closed(object? sender, EventArgs e)
        {
            media?.Dispose();
            player?.Dispose();
            libvlc?.Dispose();
        }
        /// <summary>
        /// 界面加载完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void VLCWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //播放器初始化
            libvlc = new LibVLC();
            player = new MediaPlayer(libvlc);
            //video_main.Width = this.Width;
            //video_main.Height = this.Height;
            video_main.MediaPlayer = player;
            //通过设置宽高比为窗体宽高可达到视频铺满全屏的效果
            //player.AspectRatio = this.Width + ":" + this.Height;

            //基础数据初始化
            showGrid.Visibility = Visibility.Collapsed;
            SetLocalMedia();
            listBox.SelectedIndex = UrlIndex;
            textBlockVideoContent.Text = MediaInfos[UrlIndex].Text;
            //播放器事件绑定
            player.TimeChanged += Player_TimeChanged;
            player.Playing += MediaPlayer_Playing;
            player.Paused += Player_Paused;
            player.EndReached += Player_EndReached;
        }
        /// <summary>
        /// 播放结束后
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Player_EndReached(object? sender, EventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                //停止
                if (PlayAfterTag == 1)
                {
                    //播放按钮状态
                    playButton.Visibility = Visibility.Visible;
                    pauseButton.Visibility = Visibility.Collapsed;
                    //进度条校正
                    slider.Value = slider.Maximum;
                }
            }));
            //libvlc不能调用自己，否则会死锁……这里让另外的线程来调用……
            //参考：https://stackoverflow.com/questions/56487740
            //https://github.com/ZeBobo5/Vlc.DotNet/wiki/Vlc.DotNet-freezes-(don't-call-Vlc.DotNet-from-a-Vlc.DotNet-callback)
            ThreadPool.QueueUserWorkItem((o) =>
                {
                    Dispatcher.Invoke(new Action(() =>
                    {
                        //重播
                        if (PlayAfterTag == 2)
                        {
                            SetLocalMedia();
                        }
                        //下一曲
                        else if (PlayAfterTag == 3)
                        {
                            SetNextLocalMedia();
                        }
                    }));
                });
        }
        /// <summary>
        /// 播放器暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Player_Paused(object? sender, EventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                playButton.Visibility = Visibility.Visible;
                pauseButton.Visibility = Visibility.Collapsed;
            }));
        }
        /// <summary>
        /// 播放器正在播放
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MediaPlayer_Playing(object? sender, EventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                playButton.Visibility = Visibility.Collapsed;
                pauseButton.Visibility = Visibility.Visible;
            }));
        }
        /// <summary>
        /// 播放器时间改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Player_TimeChanged(object? sender, MediaPlayerTimeChangedEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (media != null)
                {
                    slider.Maximum = media.Duration;
                    slider.Value = e.Time;
                    timeShow.Text = GetFormatTime(e.Time) + "/" + GetFormatTime(media.Duration);
                }
            }));
        }
        /// <summary>
        /// 截图
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Snapshot_Click(object sender, RoutedEventArgs e)
        {
            string dirPath = AppDomain.CurrentDomain.BaseDirectory + "snapshot\\";
            if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); }
            //string dirPath = "D:\\A\\";
            string imgName = DateTime.Now.Ticks + ".png";
            string filePath = dirPath + imgName;
            if (player != null && player.TakeSnapshot(0, filePath, (uint)this.video_main.Width, (uint)this.video_main.Height))
            {
                MessageManage.Success("已成功截图，文件路径为：" + filePath);
            }
        }
        /// <summary>
        /// 进度条值改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                //不可去操作播放器时间，防止循环调用
                //todo显示预览图
            }));
        }
        /// <summary>
        /// 进度条点击/拖动按下，需要暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slider_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null && player.WillPlay)
                {
                    if (player.IsPlaying)
                    {
                        player.SetPause(true);
                    }
                }
            }));
        }
        /// <summary>
        /// 进度条拖动抬起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slider_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null && player.WillPlay)
                {
                    var newValue = slider.Value;
                    player.Time = (long)newValue;
                    if (!player.IsPlaying)
                    {
                        player.SetPause(false);
                    }
                }
                //播放结束后拖动进度条需要重新载入播放
                else
                {
                    var time = (long)slider.Value;
                    SetLocalMedia();
                    if (player != null) player.Time = time;
                }
            }));
        }
        /// <summary>
        /// 播放/暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null && player.WillPlay)
                {
                    if (player.IsPlaying)
                    {
                        player.SetPause(true);
                    }
                    else
                    {
                        player.SetPause(false);
                    }
                }
                else
                {
                    SetLocalMedia();
                }
            }));
        }
        /// <summary>
        /// 快退
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_FastReverse_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null && player.IsPlaying)
                    player.Time -= player.Time < FastReverseTime ? player.Time : FastReverseTime;
            }));
        }
        /// <summary>
        /// 快进
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_FastForward_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null && player.IsPlaying)
                    player.Time += player.Length - player.Time < FastForwardTime ? player.Length - player.Time : FastForwardTime;
            }));
        }
        /// <summary>
        /// 上一个文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Previous_One_Click(object sender, RoutedEventArgs e) => SetPrevLocalMedia();
        /// <summary>
        /// 下一个文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Next_One_Click(object sender, RoutedEventArgs e) => SetNextLocalMedia();
        /// <summary>
        /// 重新播放
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Refresh_Click(object sender, RoutedEventArgs e) => SetLocalMedia();
        /// <summary>
        /// 列表展开/折叠
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_List_Click(object sender, RoutedEventArgs e)
        {
            if (IsListEx || this.WindowState == WindowState.Maximized)
            {
                //记录折叠前的宽度，以便恢复的时候，还是旧值
                ListWidth = columnDefinitionEx.Width.Value == 0 ? ListWidth : columnDefinitionEx.Width.Value;
                columnDefinitionEx.Width = new GridLength(0);
                IsListEx = false;
            }
            else
            {
                columnDefinitionEx.Width = new GridLength(ListWidth);
                IsListEx = true;
            }
        }
        /// <summary>
        /// 全屏切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_FullScreen_Click(object sender, RoutedEventArgs e)
        {
            if (WindowState == WindowState.Normal)
            {
                WindowState = WindowState.Maximized;
            }
            else if (WindowState == WindowState.Maximized)
            {
                WindowState = WindowState.Normal;
            }
            Dispatcher.Invoke(new Action(() =>
            {
                if (player != null)
                {
                    player.ToggleFullscreen();
                    if (player.Fullscreen)
                    {
                        canceFullScreenIconButton.Visibility = Visibility.Visible;
                        fullScreenIconButton.Visibility = Visibility.Collapsed;
                        Button_List_Click(sender, e);
                    }
                    else
                    {
                        canceFullScreenIconButton.Visibility = Visibility.Collapsed;
                        fullScreenIconButton.Visibility = Visibility.Visible;
                        Button_List_Click(sender, e);
                    }
                }
            }));
        }
        /// <summary>
        /// 列表选项切换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (sender is ListBox listBox)
            {
                UrlIndex = listBox.SelectedIndex;
                SetLocalMedia();
            }
        }
        /// <summary>
        /// 鼠标移入或移开出Grid，控制操作区显示和隐藏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Grid_MouseEnterOrLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (showGrid.Visibility == Visibility.Collapsed)
                showGrid.Visibility = Visibility.Visible;
            else if (showGrid.Visibility == Visibility.Visible)
                showGrid.Visibility = Visibility.Collapsed;
            else showGrid.Visibility = Visibility.Visible;
        }
        /// <summary>
        /// 滚轮滚动，缩放画面。缩放有异常，后续再修，暂时不采用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Video_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            //取一次缩放0.1
            var delta = e.Delta > 0 ? 0.1f : -0.1f;
            if (player?.Scale + delta <= 0 || player?.Scale + delta > 10) return;
            if (player != null) player.Scale += delta;
            AddLineLog("缩放比例设置为：" + player?.Scale);
        }
        /// <summary>
        /// 信息按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Info_Click(object sender, RoutedEventArgs e)
        {
            if (borderVideoContent.Visibility == Visibility.Collapsed || borderVideoContent.Visibility == Visibility.Hidden)
            {
                borderVideoContent.Visibility = Visibility.Visible;
            }
            else
            {
                borderVideoContent.Visibility = Visibility.Collapsed;
            }
        }
        /// <summary>
        /// 拖动窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Win_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.DragMove();
        }
        /// <summary>
        /// 关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Close_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        /// <summary>
        /// 最小化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Min_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }
        /// <summary>
        /// 最大化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Max_Click(object sender, RoutedEventArgs e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                this.WindowState = WindowState.Normal;
                Button_List_Click(sender, e);
            }
            else
            {
                this.WindowState = WindowState.Maximized;
                Button_List_Click(sender, e);

            }
            Dispatcher.Invoke(new Action(() =>
            {
                player?.ToggleFullscreen();

            }));
        }
        /// <summary>
        /// 打开/关闭播放设置界面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SettingButton_Click(object sender, RoutedEventArgs e)
        {
            settingPopup.IsOpen = !settingPopup.IsOpen;
        }
        /// <summary>
        /// combobox被选中，依赖属性的绑定有问题，要单独处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ComboBox_Selected(object sender, SelectionChangedEventArgs e)
        {
            if (sender is ComboBox box)
            {
                PlayAfterTag = (int)box.SelectedValue;
            }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 打印一行日志
        /// </summary>
        /// <param name="str"></param>
        private void AddLineLog(string str)
        {
            var ss = DateTime.Now.ToString();
            Dispatcher.Invoke(new Action(() =>
            {
                logTextBlock.Text = "[" + ss + "]" + str + "(3秒后自动清除)";
            }));
            Dispatcher.Invoke(new Action(async () =>
            {
                await Task.Delay(3000);
                logTextBlock.Text = "无";
            }));
        }
        /// <summary>
        /// 从MediaInfoWrapper中获取_filePath
        /// </summary>
        /// <param name="mediaInfo"></param>
        /// <returns></returns>
        private static string? GetPathFromMediaInfoWrapper(MediaInfoWrapper mediaInfo)
        {
            if (mediaInfo == null) return null;
            //这个库让人有点无语，文件地址应该还是比较常用的，但实体对象中没有文件地址，让人有点恼火，为了方便，用反射来拿私有的字段了.
            //当然，Text字段中也能提取到文件地址
            return mediaInfo.GetType().GetField("_filePath", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(mediaInfo)?.ToString();
        }
        /// <summary>
        /// 将MediaInfoWrapper.Text转为字典，以方便提取展示
        /// </summary>
        /// <param name="mediaInfo"></param>
        /// <returns></returns>
        private static Dictionary<string, string> GetDicFromMediaInfoWrapperText(MediaInfoWrapper mediaInfo)
        {
            if (mediaInfo == null) return [];
            var ts = mediaInfo.Text.Split("\r\n");
            var ds = new Dictionary<string, string>();
            foreach (var t in ts)
            {
                if (t.Contains(':'))
                {
                    var keyValue = t.Split(':');
                    if (keyValue.Length == 2)
                    {
                        ds.Add(keyValue[0].TrimEnd(), keyValue[1]);
                    }
                }
            }
            return ds;
        }
        /// <summary>
        /// 提取MediaInfoWrapper.Text中指定字段，示例对应关系如下（21.9.3.0版本）：
        /// <para> General </para>
        /// <para> Complete name                            : F:\Project\Assets\Videos\m3.mp4 </para>
        /// <para> Format                                   : MPEG-4 </para>
        /// <para> Format profile                           : Base Media </para>
        /// <para> Codec ID                                 : isom(isom/iso2/mp41) </para>
        /// <para> File size                                : 1.83 MiB </para>
        /// <para> Duration                                 : 37 s 245 ms </para>
        /// <para> Overall bit rate                         : 412 kb/s </para>
        /// <para> Description                              : Packed by Bilibili XCoder v2.0.2 </para>
        /// <para> Writing application                      : Lavf60.16.100 </para>
        /// <para>  </para>
        /// <para> Video </para>
        /// <para> ID                                       : 1 </para>
        /// <para> Format                                   : HEVC </para>
        /// <para> Format/Info                              : High Efficiency Video Coding </para>
        /// <para> Format profile                           : Main @L4@Main </para>
        /// <para> Codec ID                                 : hev1 </para>
        /// <para> Codec ID/Info                            : High Efficiency Video Coding </para>
        /// <para> Duration                                 : 37 s 201 ms </para>
        /// <para> Source duration                          : 37 s 199 ms </para>
        /// <para> Bit rate                                 : 242 kb/s </para>
        /// <para> Width                                    : 854 pixels </para>
        /// <para> Height                                   : 426 pixels </para>
        /// <para> Display aspect ratio                     : 2.001 </para>
        /// <para> Original display aspect ratio            : 2.000 </para>
        /// <para> Frame rate mode                          : Variable </para>
        /// <para> Frame rate                               : 30.000 FPS </para>
        /// <para> Minimum frame rate                       : 29.412 FPS </para>
        /// <para> Maximum frame rate                       : 30.303 FPS </para>
        /// <para> Color space                              : YUV </para>
        /// <para> Chroma subsampling                       : 4:2:0 </para>
        /// <para> Bit depth                                : 8 bits </para>
        /// <para> Bits/(Pixel* Frame)                       : 0.022 </para>
        /// <para> Stream size                              : 1.08 MiB(59%) </para>
        /// <para> Source stream size                       : 1.08 MiB(59%) </para>
        /// <para> Color range                              : Limited </para>
        /// <para> Color primaries                          : BT.709 </para>
        /// <para> Transfer characteristics                 : BT.709 </para>
        /// <para> Matrix coefficients                      : BT.709 </para>
        /// <para> mdhd_Duration                            : 37200 </para>
        /// <para> Codec configuration box                  : hvcC </para>
        /// <para>  </para>
        /// <para> Audio </para>
        /// <para> ID                                       : 2 </para>
        /// <para> Format                                   : AAC LC </para>
        /// <para> Format/Info                              : Advanced Audio Codec Low Complexity </para>
        /// <para> Codec ID                                 : mp4a-40-2 </para>
        /// <para> Duration                                 : 37 s 245 ms </para>
        /// <para> Bit rate mode                            : Constant </para>
        /// <para> Bit rate                                 : 159 kb/s </para>
        /// <para> Channel(s)                               : 2 channels </para>
        /// <para> Channel layout                           : L R </para>
        /// <para> Sampling rate                            : 44.1 kHz </para>
        /// <para> Frame rate                               : 43.066 FPS(1024 SPF) </para>
        /// <para> Compression mode                         : Lossy </para>
        /// <para> Stream size                              : 725 KiB(39%) </para>
        /// <para> Default                                  : Yes </para>
        /// <para> Alternate group                          : 1 </para>
        /// </summary>
        /// <param name="mediaInfo"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        private static string GetValueFromMediaInfoWrapperText(MediaInfoWrapper mediaInfo, string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key));
            }

            var ds = GetDicFromMediaInfoWrapperText(mediaInfo);
            return ds[key];
        }
        /// <summary>
        /// 设置本地播放媒体，使用MediaInfoWrapper
        /// </summary>
        /// <param name="mediaInfoWrapper"></param>
        private void SetLocalMedia(MediaInfoWrapper mediaInfoWrapper)
        {
            var url = GetPathFromMediaInfoWrapper(mediaInfoWrapper);
            if (string.IsNullOrEmpty(url)) return;
            SetLocalMedia(url);
        }
        /// <summary>
        /// 设置本地播放媒体，默认使用当前播放序列号
        /// </summary>
        private void SetLocalMedia()
        {
            SetLocalMedia(MediaUrls[UrlIndex].Value);
        }
        /// <summary>
        /// 播放下一个
        /// </summary>
        private void SetNextLocalMedia()
        {
            UrlIndex++;
            listBox.SelectedIndex = UrlIndex;
            SetLocalMedia();
        }
        /// <summary>
        /// 播放上一个
        /// </summary>
        private void SetPrevLocalMedia()
        {
            UrlIndex--;
            listBox.SelectedIndex = UrlIndex;
            SetLocalMedia();
        }
        /// <summary>
        /// 设置本地播放媒体，使用url
        /// </summary>
        /// <param name="url"></param>
        private void SetLocalMedia(string url)
        {
            url = Path.GetFullPath(url);
            if (!string.IsNullOrEmpty(url) && libvlc != null && player != null)
            {
                media?.Dispose();
                //player.Media?.Dispose();
                media = new Media(libvlc, new Uri(url));
                //media = new Media(libvlc, new Uri(url), options: [":repeat", ":no-audio"]);
                //media?.AddOption(":rotate-angle=<90>");
                //media?.AddOption(":no-audio");
                //media?.AddOption(":repeat");
                //player.Dispose();
                //player = new(libvlc);
                //video_main.MediaPlayer = player;

                //设置初始缩放比例（单向满屏效果）
                #region 异常代码，待后续研究
                //uint width = 0;
                //uint height = 0;
                //int width1 = 0;
                //int height1 = 0;
                //获取播放器的高度宽度，无法获取，一直都失败
                //var re = player?.Size(0, ref width, ref height);//返回false
                //var r2 = player?.Cursor(0, ref width1, ref height1);//返回false

                //设置缩放比例，无法正常匹配，会乱
                //MediaInfoWrapper的构造有bug，对于logger写的是可传入为空，但实际却没考虑空的情况，源码中直接就调用了，实际使用时必须要传实体才行，否者会报空引用错误
                //var mediaInfo = new MediaInfoWrapper(url, logger);
                //if (player.WillPlay)
                //{
                //    player.Scale = mediaInfo.Width / (this.Width - (IsListEx ? ListWidth : 0)) > mediaInfo.Height / (this.Height - CaptionHeigth) ?
                //        (float)((this.Width - (IsListEx ? ListWidth :0)) / mediaInfo.Width) : //以宽度为基准
                //        (float)((this.Height - CaptionHeigth) / mediaInfo.Height);//以高度为基准
                //}

                //AddLineLog("缩放比例设置为：" + player.Scale);
                #endregion


                player.Play(media);
                //设置进度条
                slider.Maximum = media.Duration;

                //player.Scale = player.Scale;
            }
        }
        /// <summary>
        /// 获取指定格式时间
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        static private string GetFormatTime(long time)
        {
            TimeSpan timeSpan = TimeSpan.FromMilliseconds(time);
            return $"{timeSpan.Days:00}:{timeSpan.Hours:00}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}:{timeSpan.Milliseconds:000}";
        }
        #endregion
    }
}
